/*
 * ThreadHandler.cpp
 *
 *  Created on: 2012-12-18
 *      Author: yangentao@gmail.com
 */

#include "ThreadHandler.h"
#include "Log.h"

namespace yet {

ThreadHandler::ThreadHandler() {
	active = false;
}
ThreadHandler::~ThreadHandler() {
	assert(!thread.inThread());
	if (isActive()) {
		Log << warn << "Thread is Running when Thread Handler destructor." << endl;
		quit();
	}
	waitFinish();
}
boost::signals2::connection ThreadHandler::addHandler(const MsgHandler& msgHandler) {
	AutoLock al(this);
	return sig.connect(msgHandler);
}

void ThreadHandler::post(Message msg, bool front) {
	if (front) {
		messages.push_front(msg);
	} else {
		messages.push_back(msg);
	}
	notify();
}
void ThreadHandler::postFront(Message msg) {
	post(msg, true);
}
void ThreadHandler::postQuitMessage() {
	Message q;
	q.quit = true;
	post(q);
}

DWORD ThreadHandler::waitFinish(DWORD millSeconds) {
	return thread.waitFinish(millSeconds);
}
void ThreadHandler::setPriority(Thread::Priority p) {
	thread.setPriority(p);
}
bool ThreadHandler::start() {
	assert(!isActive());
	AutoLock al(this);
	thread.OnRun = boost::bind(&ThreadHandler::onLoop, this, _1);
	active = thread.start(0, true);
	thread.resume();
	return active;
}
void ThreadHandler::notify() {
	event.notify();
}

void ThreadHandler::cancelMsg() {
	if (OnCancel) {
		AutoLock al(messages);
		while (!messages.isEmpty()) {
			OnCancel(messages.pop_back());
		}
	}
}
void ThreadHandler::quit() {
	active = false;
	notify();
	thread.waitFinish();
	cancelMsg();
}
bool ThreadHandler::isActive() {
	AutoLock al(this);
	return active;
}

DWORD ThreadHandler::onLoop(void*) {
	int exitCode = 0;
	do {
		while (active) {
			AutoLock al(messages);
			if (messages.isEmpty()) {
				break;
			}
			Message msg = messages.pop_front();
			al.unLock();
			if (msg.isQuit()) {
				active = false;
				exitCode = msg.argN;
				goto cancelAll;
			}
			if (OnMessage) {
				OnMessage(msg);
			}
			if (!sig.empty()) {
				sig(msg);
			}
		}
		if (!active) {
			return 0;
		}
		event.wait();
	} while (true);
	active = false;
	cancelAll: cancelMsg();
	return exitCode;
}

} /* namespace yet */
